﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using X23.Model;
using X23.Util.DateTimeUtil;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

namespace X23.EFCore.Repository
{

    public class Repository<T> : IRepository<T> where T : BaseAuditedEntity
    {
        private DbSet<T> _entities;
        private readonly string _currentUserName;
        private readonly EFCoreContext _dbContext;

        public Repository(EFCoreContext eFCoreContext, IHttpContextAccessor httpContextAccessor)
        {
            //var userInfo = httpContextAccessor.HttpContext.User.Claims.Where(x => x.Type == ClaimTypes.UserData).FirstOrDefault()?.Value;
            _currentUserName = httpContextAccessor.HttpContext?.User.Identity?.Name;
            _dbContext = eFCoreContext;
        }

        public DbSet<T> Entities
        {
            get
            {
                if (_entities == null)
                    _entities = _dbContext.Set<T>();
                return _entities;
            }
        }
        public async Task<bool> AddAsync(T entity)
        {
            entity.CreateBy = _currentUserName;
            await Entities.AddAsync(entity);
            var result = await _dbContext.SaveChangesAsync();
            return result > 0;
        }

        public async Task<bool> UpdateAsync(T entity)
        {
            var oldData = await GetByIdAsync(entity.Id);
            entity.CreateBy = oldData.CreateBy;
            entity.CreateTime = oldData.CreateTime;
            entity.UpdateBy = _currentUserName;
            entity.UpdateTime = DateTimeUtil.DateTimeChineseNow;
            var result = await _dbContext.SaveChangesAsync();
            return result > 0;
        }

        public async Task<T> GetByIdAsync(object id)
        {
            var result = await Entities.FindAsync(id);
            if (result == null)
            {
                throw new Exception($"数据库未找到实体对象：{typeof(T).Name},id={id}");
            }
            return result;
        }

        public async Task<bool> DeleteAsync(object id, bool isPhysicalDelete = false)
        {
            var entity = await GetByIdAsync(id);
            if (isPhysicalDelete)
            {
                Entities.Remove(entity);
                return await _dbContext.SaveChangesAsync() > 0;
            }
            else
            {
                entity.IsDelete = true;
                return await UpdateAsync(entity);
            }
        }

        public async Task<IQueryable<T>> GetAllAsync(bool ignore = false)
        {
            return await Task.FromResult(TableNoTracking(ignore));
        }

        public async Task<bool> AddListAsync(List<T> entities)
        {
            for (int i = 0; i < entities.Count; i++)
            {
                var item = entities[i];
                item.CreateBy = _currentUserName;
                await Entities.AddAsync(item);
            }
            var result = await _dbContext.SaveChangesAsync();
            return result > 0;
        }

        public async Task<bool> DeleteListAsync(Expression<Func<T, bool>> predicate, bool isPhysicalDelete = false)
        {
            var entities = Entities.Where(predicate).ToList();
            entities.ForEach(item =>
            {
                if (isPhysicalDelete)
                {
                    Entities.Remove(item);
                }
                else
                {
                    item.IsDelete = true;
                    item.UpdateBy = _currentUserName;
                    item.UpdateTime = DateTimeUtil.DateTimeChineseNow;
                }
            });
            return await _dbContext.SaveChangesAsync() > 0;
        }

        public IQueryable<T> Table(bool ignore = false)
        {
            return Entities.Ignore(ignore);
        }

        public IQueryable<T> TableNoTracking(bool ignore = false)
        {
            return Entities.AsQueryable().Ignore(ignore);
        }

        //public bool Add(T entity)
        //{
        //    entity.CreateBy = _currentUserName;
        //    Entities.Add(entity);
        //    return _dbContext.SaveChanges() > 0;
        //}
        //public bool Update(T entity)
        //{
        //    var oldData = GetById(entity.Id);
        //    entity.CreateBy = oldData.CreateBy;
        //    entity.CreateTime = oldData.CreateTime;
        //    entity.UpdateBy = _currentUserName;
        //    entity.UpdateTime = DateTimeUtil.DateTimeChineseNow;
        //    return _dbContext.SaveChanges() > 0;
        //}

        //public bool Delete(object id, bool isPhysicalDelete = false)
        //{
        //    var entity = GetById(id);
        //    if (isPhysicalDelete)
        //    {
        //        Entities.Remove(entity);
        //        return _dbContext.SaveChanges() > 0;
        //    }
        //    else
        //    {
        //        entity.IsDelete = true;
        //        return Update(entity);
        //    }
        //}

        //public T GetById(object id)
        //{
        //    return Entities.Find(id);
        //}

        //public IQueryable<T> Table
        //{
        //    get
        //    {
        //        return Entities;
        //    }
        //}

        //public virtual IQueryable<T> TableNoTracking
        //{
        //    get
        //    {
        //        return Entities.AsNoTracking();
        //    }
        //}

    }

    public static class QueryableExpansion
    {

        public static IQueryable<T> Ignore<T>(this IQueryable<T> query, bool ignore) where T : BaseAuditedEntity
        {
            if (!ignore)
            {
                query = query.Where(x => x.IsDelete == false);
            }
            return query;
        }
    }

}
